package middleware

import (
	"ginblog/utils"
	"ginblog/utils/errmsg"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt"
	"net/http"
	"strings"
	"time"
)

var JwtKey = []byte(utils.JwtKey) // 设定密码

/**
 ** 定义需求,即我们需要通过jwt传输的数据,
 **	例如需要传输Username和Password,定义如下结构体
 */
type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

var code int

// 生成 jwt token
func SetToken(username string) (string, int) {
	expireTime := time.Now().Add(time.Hour * 10) // 设置过期时间
	SetClaims := MyClaims{
		Username: username,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    "ginblog",
		},
	}

	/**
	 ** NewWithClaims 方法根据自定义 Claims 结构体创建 Token 示例
	 ** SignedString  方法根据传入的空接口类型参数 key, 返回完整的签名令牌
	 */
	token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, SetClaims).SignedString(JwtKey)

	if err != nil {
		return "", errmsg.ERROR
	}
	return token, errmsg.SUCCESS
}

// 验证 jwt token
func CheckToken(token string) (*MyClaims, int) {
	tokenClaims, _ := jwt.ParseWithClaims(token, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return JwtKey, nil
	})

	if claims, ok := tokenClaims.Claims.(*MyClaims); ok && tokenClaims.Valid {
		return claims, errmsg.SUCCESS
	} else {
		return nil, errmsg.ERROR
	}

}

// jwt中间件
func JwtToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenHeader := c.Request.Header.Get("authorization")
		if tokenHeader == "" {
			code = errmsg.ErrorTokenExist
			c.JSON(http.StatusOK, gin.H{
				"code":    code,
				"message": errmsg.GetErrMsg(code),
			})
			c.Abort()
			return
		}

		checkToken := strings.SplitN(tokenHeader, " ", 2)
		if len(checkToken) != 2 && checkToken[0] != "Bearer" {
			code = errmsg.ErrorTokenWrong
			c.JSON(http.StatusOK, gin.H{
				"code":    code,
				"message": errmsg.GetErrMsg(code),
			})
			c.Abort()
			return
		}

		key, tCode := CheckToken(checkToken[1])
		if tCode == errmsg.ERROR {
			code = errmsg.ErrorTokenWrong
			c.JSON(http.StatusOK, gin.H{
				"code":    code,
				"message": errmsg.GetErrMsg(code),
			})
			c.Abort()
			return
		}
		if time.Now().Unix() > key.ExpiresAt {
			code = errmsg.ErrorTokenRuntime
			c.JSON(http.StatusOK, gin.H{
				"code":    code,
				"message": errmsg.GetErrMsg(code),
			})
			c.Abort()
			return
		}

		c.Set("username", key.Username)
		c.Next()

	}
}
